package com.xjrsoft.common.im;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.module.im.entity.ImMessage;
import com.xjrsoft.module.im.entity.ImUnread;
import com.xjrsoft.module.im.service.IImMessageService;
import com.xjrsoft.module.im.service.IImUnreadService;
import com.xjrsoft.module.organization.service.IUserService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;

/**
 * WebSocket 连接测试
 */
@Component
@ServerEndpoint("/im/{satoken}")
@AllArgsConstructor
public class WebSocketConnect {

    private final IImMessageService imMessageService;

    private final IImUnreadService imUnreadService;

    /**
     * 固定前缀
     */
    private static final String USER_ID = "user_id_";

    /**
     * 存放Session集合，方便推送消息 （javax.websocket.Session）
     */
    private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();

    // 监听：连接成功
    @OnOpen
    public void onOpen(Session session, @PathParam("satoken") String satoken) throws IOException {

        // 根据 token 获取对应的 userId
        Object loginId = StpUtil.getLoginIdByToken(satoken);
        if (loginId == null) {
            session.close();
            throw new SaTokenException("连接失败，无效Token：" + satoken);
        }

        // put到集合，方便后续操作
        long userId = SaFoxUtil.getValueByType(loginId, long.class);
        sessionMap.put(USER_ID + userId, session);

        LambdaQueryWrapper<ImUnread> eq = Wrappers.lambdaQuery(ImUnread.class).eq(ImUnread::getTo, userId);

        //如果当前登陆人有未读消息
        if (imUnreadService.count(eq) > 0) {
            List<ImUnread> list = imUnreadService.list(eq);
            List<ImMessage> imMessages = JSONUtil.toBean(JSONUtil.toJsonStr(list), new TypeReference<List<ImMessage>>() {
            }, true);
            sendMultiMessage(userId, imMessages);

			imMessageService.saveBatch(imMessages);
			imUnreadService.removeByIds(list);
        }

    }

    // 监听: 连接关闭
    @OnClose
    public void onClose(Session session) {
        System.out.println("连接关闭，sid=" + session.getId());
        for (String key : sessionMap.keySet()) {
            if (sessionMap.get(key).getId().equals(session.getId())) {
                sessionMap.remove(key);
            }
        }
    }

    // 监听：收到客户端发送的消息
    @OnMessage
    public void onMessage(Session session, String message) {
        ImMessage imMessage = JSONUtil.toBean(message, ImMessage.class);

        //判断对方在不在线
        if (sessionMap.containsKey(USER_ID + imMessage.getTo())) {
            //接收到消息 如果没有接收人 就代表所有人
            if (ObjectUtil.isNotNull(imMessage.getTo())) {
                sendMessage(imMessage.getTo(), imMessage);
                imMessageService.save(imMessage);
            }
        }
        //如果不在线  存入未读数据
        else {
            ImUnread imUnread = JSONUtil.toBean(message, ImUnread.class);

            imUnreadService.save(imUnread);
        }

        System.out.println("sid为：" + session.getId() + "，发来：" + message);
    }

    // 监听：发生异常
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("sid为：" + session.getId() + "，发生错误");
        error.printStackTrace();
    }

    // ---------

    // 向指定客户端推送消息
    public static void sendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 向指定用户推送消息
    public static void sendMessage(long userId, ImMessage message) {
        Session session = sessionMap.get(USER_ID + userId);
        if (session != null) {
            sendMessage(session, JSONUtil.toJsonStr(message));
        }
    }


    // 向指定用户推送消息
    public static void sendMultiMessage(long userId, List<ImMessage> message) {
        Session session = sessionMap.get(USER_ID + userId);
        if (session != null) {
            sendMessage(session, JSONUtil.toJsonStr(message));
        }
    }

}
